home *** CD-ROM | disk | FTP | other *** search
/ Shareware Super Platinum 8 / Shareware Super Platinum 8.iso / mac / PROGTOOL / PASSDK30.ZIP;1 / DISK1.ZIP / PAS / SUBS / MVSOUND / MVSOUND.ASM < prev    next >
Encoding:
Assembly Source File  |  1993-03-17  |  51.5 KB  |  2,134 lines

  1. ;$Author:   DCODY  $
  2. ;$Date:   17 Mar 1993 13:10:16  $
  3. ;$Header:   X:/sccs/mvsound/mvsound.asv   1.9   17 Mar 1993 13:10:16   DCODY  $
  4. ;$Log:   X:/sccs/mvsound/mvsound.asv  $
  5. ;  
  6. ;     Rev 1.9   17 Mar 1993 13:10:16   DCODY
  7. ;  changed FindDMABuffer to pre-condition the buffer to align on a 4k page if
  8. ;  the buffer size is greater that or equal to 4k. This will allow 4k DMA 
  9. ;  buffers to run under Windows is a DOS box.
  10. ;  
  11. ;     Rev 1.8   24 Feb 1993 16:15:28   DCODY
  12. ;  removed clearing the dma buffer with 80 hex. removed a check on the smallest
  13. ;  dma buffer allowed in findthedmabuffer routine.
  14. ;  
  15. ;     Rev 1.7   08 Dec 1992 16:55:46   DCODY
  16. ;  moved externADDR macros for Borland link.
  17. ;  
  18. ;     Rev 1.6   24 Sep 1992 08:54:22   DCODY
  19. ;  changed MVGetHardware to mvGetHardware
  20. ;  
  21. ;     Rev 1.5   12 Aug 1992 17:13:18   DCODY
  22. ;  made call to mvgethardware use a zero (0) parameter to use the current base.
  23. ;  
  24. ;     Rev 1.4   17 Jul 1992 14:18:22   DCODY
  25. ;  moved TheDMAchannel and TheIRQchannel out to another module. Made the
  26. ;  hardware I/O relocatable. Made initmvsound recallable without ill effects.
  27. ;  
  28. ;     Rev 1.3   09 Jul 1992 10:07:50   DCODY
  29. ;  corrected MV101 bit test and jumps
  30. ;  
  31. ;     Rev 1.2   26 Jun 1992 14:13:48   DCODY
  32. ;  added the parameter to GetHWVersion call
  33. ;  
  34. ;     Rev 1.1   23 Jun 1992 17:06:04   DCODY
  35. ;  PAS2 update
  36. ;  
  37. ;     Rev 1.0   15 Jun 1992 09:43:46   BCRANE
  38. ;  Initial revision.
  39. ;$Logfile:   X:/sccs/mvsound/mvsound.asv  $
  40. ;$Modtimes$
  41. ;$Revision:   1.9  $
  42. ;$Workfile:   mvsound.asm  $ 
  43.  
  44.         page    64,131
  45.     Title    MVSOUND  --  Pro Audio Spectrum Sound Support Code
  46.  
  47. ;   /*\
  48. ;---|*|----====< MVSOUND >====----
  49. ;---|*|
  50. ;---|*|  This module contains the code for supporting PCM I/O.
  51. ;---|*|
  52. ;---|*|  Media Vision, Inc. Copyright (c) 1991,1992. All Rights Reserved.
  53. ;---|*|
  54. ;   \*/
  55.  
  56. ;
  57. ; The following set of equates are used to control what routines are compiled
  58. ; by doing this, MVSOUND.ASM can contain all the necessary code in one file,
  59. ; but generate separate, linkable objects with just the necessary code.
  60. ;
  61. ALLOBJS     = 0     ; individual objects are being built
  62. DATAOBJ     = 0     ; data code to be compiled
  63. MISC1OBJ    = 0     ; minimum code needed from the library
  64. MISC2OBJ    = 0     ; other miscellaneous code
  65. PCMOBJ        = 0     ; PCM code to be compiled
  66.  
  67. ifdef BUILDDATA
  68.   DATAOBJ   = 1     ; data code to be compiled
  69. endif
  70.  
  71. ifdef BUILDMISC1
  72.   MISC1OBJ  = 1     ; misc module #1 code to be compiled
  73. endif
  74.  
  75. ifdef BUILDMISC2
  76.   MISC2OBJ  = 1     ; misc module #2 code to be compiled
  77. endif
  78.  
  79. ifdef BUILDPCM
  80.   PCMOBJ    = 1     ; data code to be compiled
  81. endif
  82.  
  83. ifdef BUILDALL
  84.   ALLOBJS   = 1     ; all objects are being built
  85.   DATAOBJ   = 1     ; data code to be compiled
  86.   MISC1OBJ  = 1     ; miscellaneous code to be compiled
  87.   MISC2OBJ  = 1     ; miscellaneous code to be compiled
  88.   PCMOBJ    = 1     ; PCM code to be compiled
  89. endif
  90.  
  91.     .xlist
  92.     include model.inc
  93.         include masm.inc
  94.     include target.inc
  95.     include state.inc
  96.     include common.inc
  97.     .list
  98.  
  99. ;
  100. ; structure for pointing to the above table of DMA addresses
  101. ;
  102.  
  103. dmaaddr struc
  104. _dmach        db    ?    ; DMA channel selected
  105. _dmardstat      db      ?       ; DMA read status
  106. _dmawrcntrl    db    ?    ; DMA write command register
  107. _dmawreq    db    ?    ; DMA write request register
  108. _dmawrsmr    db    ?    ; DMA write single mask register
  109. _dmawrmode    db    ?    ; DMA write mode register
  110. _dmaclear    db    ?    ; DMA clear low/high flip-flop
  111. _dmardtemp    db    ?    ; DMA read temp register
  112. _dmawrclr    db    ?    ; DMA write master clear
  113. _dmaclrmsk    db    ?    ; DMA clear mask register
  114. _dmawrall    db    ?    ; DMA write all mask register bits
  115. dmaaddr ends
  116.  
  117. ;
  118. ;---------------------------========================---------------------------
  119. ;---------------------------====< DATA SECTION >====---------------------------
  120. ;---------------------------========================---------------------------
  121. ;
  122.     externADDR  MVInitStatePtr          ; pointer to the state table init code
  123.     externADDR    mvGetHWVersion        ; returns the hardware bits
  124.  
  125. if MODELSIZE eq 0
  126.     .code
  127. else
  128.     .data
  129. endif
  130.  
  131. if DATAOBJ                              ; include if we are building DATA.OBJ
  132.  
  133. ;
  134. ; These variables are DMA/Buffer control variables
  135. ;
  136. TheIRQMask    db    INT7MSK     ; 8259 interrupt mask
  137.  
  138. TheDMAMode    db    00h        ; 44h for input, 48h for output
  139. LinearPtr    dd    0        ; holds linear address
  140. SegmentedPtr    dd    0        ; holds segmented address (real mode)
  141. DMABuffLength    dw    0        ; DMA Length (0 based) (MUST BE EVEN!)
  142. DMABuffDivides    db    0        ; # of splits in the DMA buffer
  143.  
  144. TheSampleRate    dd    0        ; 3k through 88k
  145. StereoMono    db    0        ; ff for mono, 00 for stereo
  146. PCMDirection    db    0        ; bit mask for the DMA controller
  147. SampleSize    db    0        ; sample size: 0=8,1=12,2=16
  148.  
  149.     public    DMAAutoInit        ; TRUE(0ffh) or FALSE(000h)
  150. DMAAutoInit    db    0ffh        ; to allow auto-init on DMA access
  151.  
  152. UserRoutine     dd      0               ; User Code
  153.  
  154. StatusWord      dw      0               ; Holds current status:
  155. ;                    ;   0 = inactive, available
  156. ;                    ;   1 = currently playing
  157. ;                    ;   2 = currently recording
  158.  
  159. OldIRQRoutine   dd      0               ; holds the original routine
  160.  
  161. polledmask    equ    bICsamprate+bICsampbuff ; polled mask
  162. dmamask     equ    bICsampbuff        ; dma mask
  163.  
  164. DMAOUTPUT    equ    0+dmamask    ; DMA is used to drive the output
  165. POLLEDOUTPUT    equ    0+polledmask    ; Polling routine drives output
  166. DMAINPUT    equ    1+dmamask    ; DMA is used to read input
  167. POLLEDINPUT    equ    1+polledmask    ; Polling routine reads input
  168. TypeOfSetup    db    0        ; polled/dma interrupt masks & stuff..
  169.  
  170.     public    NumberOfInterrupts
  171. NumberOfInterrupts      dw      0       ; number of interrupts that have occured
  172. ;
  173. ; These variables direct our code to the proper DMA channel
  174. ;
  175. OurDMAPageReg    dw    CH1PAGEREG    ; default to DMA channel 1 page reg
  176. OurDMAddress    dw    DMAC1ADDR    ; default to DMA channel 1 address reg
  177.  
  178. ;
  179. ; table of address pointers to the various DMA 2 addresses
  180. ;
  181.         public  DMA1AddrTable
  182. DMA1AddrTable    label    byte
  183.     db    DEFAULTDMA    ; DMA channel selected
  184.         db      DMARDSTAT       ; DMA read status
  185.     db    DMAWRCNTRL    ; DMA write command register
  186.     db    DMAWREQ     ; DMA write request register
  187.     db    DMAWRSMR    ; DMA write single mask register
  188.     db    DMAWRMODE    ; DMA write mode register
  189.     db    DMACLEAR    ; DMA clear low/high flip-flop
  190.     db    DMARDTEMP    ; DMA read temp register
  191.     db    DMAWRCLR    ; DMA write master clear
  192.     db    DMACLRMSK    ; DMA clear mask register
  193.     db    DMAWRALL    ; DMA write all mask register bits
  194. ;
  195. ; table of address pointers to the various DMA 2 addresses
  196. ;
  197.     public    DMA2AddrTable
  198. DMA2AddrTable   label   byte
  199.         db      DEFAULTDMA      ; DMA channel selected
  200.     db    DMA2RDSTAT    ; DMA read status
  201.     db    DMA2WRCNTRL    ; DMA write command register
  202.     db    DMA2WREQ    ; DMA write request register
  203.     db    DMA2WRSMR    ; DMA write single mask register
  204.     db    DMA2WRMODE    ; DMA write mode register
  205.     db    DMA2CLEAR    ; DMA clear low/high flip-flop
  206.     db    DMA2RDTEMP    ; DMA read temp register
  207.     db    DMA2WRCLR    ; DMA write master clear
  208.     db    DMA2CLRMSK    ; DMA clear mask register
  209.     db    DMA2WRALL    ; DMA write all mask register bits
  210.  
  211.     public    DMAPointer
  212. DMAPointer      dw      offset DMA1AddrTable    ; default to channel 1 table
  213. ;
  214. ; working variables
  215. ;
  216. ;
  217.     public    TheIRQMask        ; 8259 interrupt mask
  218.     public    TheDMAMode        ; 55h for input, 59h for output
  219.     public    LinearPtr        ; holds linear address
  220.     public    SegmentedPtr        ; holds segmented address (real mode)
  221.     public    DMABuffLength        ; DMA Length (0 based) (MUST BE EVEN!)
  222.     public    DMABuffDivides        ; # of splits in the DMA buffer
  223.     public    TheSampleRate        ; 3k through 88k
  224.     public    StereoMono        ; ff for mono, 00 for stereo
  225.     public    PCMDirection        ; bit mask for the DMA controller
  226.     public    SampleSize        ; sample size: 0=8,1=12,2=16
  227.     public    DMAAutoInit        ; TRUE/FALSE flag for DMA autoinit bit
  228.     public    UserRoutine        ; User Code
  229.     public    StatusWord        ; Holds current status:
  230.     public    OldIRQRoutine        ; holds the original routine
  231. polledmask    equ    bICsamprate+bICsampbuff ; polled mask
  232. dmamask     equ    bICsampbuff        ; dma mask
  233. DMAOUTPUT    equ    0+dmamask    ; DMA is used to drive the output
  234. POLLEDOUTPUT    equ    0+polledmask    ; Polling routine drives output
  235. DMAINPUT    equ    1+dmamask    ; DMA is used to read input
  236. POLLEDINPUT    equ    1+polledmask    ; Polling routine reads input
  237.     public    TypeOfSetup        ; polled/dma interrupt masks & stuff..
  238.     public    NumberOfInterrupts    ; number of interrupts that have occured
  239.     public    OurDMAPageReg        ; default to DMA channel 1 page reg
  240.     public    OurDMAddress        ; default to DMA channel 1 address reg
  241.  
  242. else    ; not building DATA.OBJ, declare all publics
  243.  
  244.     extrn    DMAPointer    :word    ; pointer to the DMA address table
  245.     extrn    DMA1AddrTable    :byte    ; 1st DMA controller table
  246.     extrn    DMA2AddrTable    :byte    ; 2nd DMA controller table
  247.     extrn    TheIRQMask    :byte    ; 8259 interrupt mask
  248.     extrn    TheDMAMode    :byte    ; 55h for input, 59h for output
  249.     extrn    LinearPtr    :dword    ; holds linear address
  250.     extrn    SegmentedPtr    :dword    ; holds segmented address (real mode)
  251.     extrn    DMABuffLength    :word    ; DMA Length (0 based) (MUST BE EVEN!)
  252.     extrn    DMABuffDivides    :byte    ; # of splits in the DMA buffer
  253.     extrn    TheSampleRate    :dword    ; 3k through 88k
  254.     extrn    StereoMono    :byte    ; ff for mono, 00 for stereo
  255.     extrn    PCMDirection    :byte    ; bit mask for the DMA controller
  256.     extrn    SampleSize    :byte    ; sample size: 0=8,1=12,2=16
  257.     extrn    DMAAutoInit    :byte    ; TRUE/FALSE flag for DMA autoinit bit
  258.     extrn    UserRoutine    :dword    ; User Code
  259.     extrn    StatusWord    :word    ; Holds current status:
  260.     extrn    OldIRQRoutine    :dword    ; holds the original routine
  261.     extrn    TypeOfSetup    :byte    ; polled/dma interrupt masks & stuff..
  262.     extrn    NumberOfInterrupts:word ; number of interrupts that have occured
  263.     extrn    OurDMAPageReg    :word    ; default to DMA channel 1 page reg
  264.     extrn    OurDMAddress    :word    ; default to DMA channel 1 address reg
  265.  
  266.  
  267. polledmask    equ    bICsamprate+bICsampbuff ; polled mask
  268. dmamask     equ    bICsampbuff        ; dma mask
  269. DMAOUTPUT    equ    0+dmamask    ; DMA is used to drive the output
  270. POLLEDOUTPUT    equ    0+polledmask    ; Polling routine drives output
  271. DMAINPUT    equ    1+dmamask    ; DMA is used to read input
  272. POLLEDINPUT    equ    1+polledmask    ; Polling routine reads input
  273. SHADOWTABLELEN  equ     28              ; 28 entries in the shadow data table
  274.  
  275. endif
  276.  
  277.     extrn    TheDMAChannel      :byte ; defaults to channel 1
  278.     extrn    TheIRQChannel      :byte ; defaults to IRQ 7
  279.  
  280.         extrn   mvhwShadowPointer :dword; a common variable for all
  281.     extrn    _MVHWVersionBits  :word ; hardware state bits
  282.     extrn    _MVTranslateCode   :word
  283.  
  284.     .code
  285.  
  286. ;
  287. ; TEXT SEGMENT externals for the different modules
  288. ;
  289.  
  290. if PCMOBJ AND (NOT ALLOBJS)        ; added for independent PCMOBJ module
  291.     externADDR    SelectIRQ        ; PCM uses "SelectIRQ"
  292.     externADDR    _unloadirqvector    ; PCM uses "_unloadirqvector"
  293.     externADDR    _getirqoffset        ; PCM uses "_getirqoffset"
  294. endif
  295.  
  296. ;
  297. ;---------------------------========================---------------------------
  298. ;---------------------------====< CODE SECTION >====---------------------------
  299. ;---------------------------========================---------------------------
  300. ;
  301. ;   /*\
  302. ;---|*|
  303. ;---|*|---------------====< Prototypes >====---------------
  304. ;---|*|
  305. ;---|*| void far *DMABuffer(char far *, int, int )
  306. ;---|*|
  307. ;---|*|     Passes in a pointer and length to the buffer.
  308. ;---|*|     Also flushes the buffer. Returns 0 or true DMA buffer ptr.
  309. ;---|*|
  310. ;---|*| int EnablePCMPlay()
  311. ;---|*|
  312. ;---|*|     Sets up the PCM hardware for polled output
  313. ;---|*|
  314. ;---|*| int EnablePCMRecord()
  315. ;---|*|
  316. ;---|*|     Sets up the PCM hardware for polled input
  317. ;---|*|
  318. ;---|*| char huge *FindDMABuffer(char huge *, int )
  319. ;---|*|
  320. ;---|*|     Takes a memory address & return the next 64k boundary
  321. ;---|*|
  322. ;---|*| MVState far *InitMVSound()
  323. ;---|*|
  324. ;---|*|     Initializes the int 2F interface & some global variables.
  325. ;---|*|
  326. ;---|*| int InitPCM()
  327. ;---|*|
  328. ;---|*|     Initializes the PCM code.
  329. ;---|*|
  330. ;---|*| void PausePCM()
  331. ;---|*|
  332. ;---|*|     Temporarily stops the PCM I/O by disabling the timers
  333. ;---|*|
  334. ;---|*| int PCMInfo( long ,int, int, int )
  335. ;---|*|
  336. ;---|*|     Sets up the transfer rate & stereo/mono/compression/data size
  337. ;---|*|
  338. ;---|*| int PCMPlay()
  339. ;---|*|
  340. ;---|*|     Starts the DMA feeding the DAC
  341. ;---|*|
  342. ;---|*| int PCMRecord()
  343. ;---|*|
  344. ;---|*|     Starts the DMA reading the ADC
  345. ;---|*|
  346. ;---|*| void RemovePCM()
  347. ;---|*|
  348. ;---|*|     kills the PCM code.
  349. ;---|*|
  350. ;---|*| void ResumePCM()
  351. ;---|*|
  352. ;---|*|     Restarts the PCM I/O by enabling the timers
  353. ;---|*|
  354. ;---|*| int SelectDMA( int )
  355. ;---|*|
  356. ;---|*|     Selects the DMA channel 1, or 3
  357. ;---|*|
  358. ;---|*| int SelectIRQ( int )
  359. ;---|*|
  360. ;---|*|     Selects the IRQ line for DMA control
  361. ;---|*|
  362. ;---|*| void StopPCM()
  363. ;---|*|
  364. ;---|*|     Turn off the PCM timers, interrupts, and state machine.
  365. ;---|*|
  366. ;---|*| void UserFunc((*long)())
  367. ;---|*|
  368. ;---|*|     Call back routine when Half way buffer is full/empty.
  369. ;---|*|
  370. ;   \*/
  371.  
  372. if PCMOBJ
  373.  
  374. ;   /*\
  375. ;---|*|------====< void far * DMABuffer( char far *, int, int ) >====------
  376. ;---|*|
  377. ;---|*| Passes in a pointer and length to the buffer
  378. ;---|*|
  379. ;---|*| Entry Conditions:
  380. ;---|*|     dParm1 points to DMA buffer
  381. ;---|*|     wParm3 points to the length (wParm3 * 1024 is the total length )
  382. ;---|*|     wParm4 is the # of divisions of the DMA buffer
  383. ;---|*|
  384. ;---|*| Exit Conditions:
  385. ;---|*|     DX:AX = 0 - bad buffer
  386. ;---|*|     DX:AX = returns buffer pointer
  387. ;---|*|
  388. ;   \*/
  389.  
  390.     public    DMABuffer
  391. DMABuffer    proc
  392.         push    bp
  393.     mov    bp,sp
  394.     push    es
  395.     push    di
  396.  
  397.     mov    cx,wParm3        ; get the dma size (4/8/16/32/64)
  398.     cmp    cx,64            ; too high?
  399.     ja    dmabbad         ; yes, bomb out
  400.  
  401.         mov     ax,1024
  402.     cwd
  403.     mul    cx            ; get the length - 1
  404.     dec    ax
  405.     mov    [DMABuffLength],ax    ; and save for later use
  406.  
  407.     les    di,dParm1        ; get the far pointer to the buffer
  408.  
  409.         mov     ax,di
  410.     mov    bx,es            ; convert it to a linear address
  411.     mov    dx,es
  412.     mov    cl,4
  413.     rol    dx,cl
  414.     and    dx,000fh
  415.     shl    bx,cl            ; add offset portion of seg to offset
  416.     add    ax,bx
  417.     jc    dmabbad         ; bad if extends over a 64k boundary
  418.  
  419.     mov    wptr [LinearPtr+0],ax    ; save the linear address
  420.     mov    wptr [LinearPtr+2],dx
  421.     mov    wptr [SegmentedPtr+0],di
  422.     mov    wptr [SegmentedPtr+2],es
  423.  
  424.     mov    bx,wParm4        ; get the # of DMA buffer divisions
  425.     mov    [DMABuffDivides],bl
  426.  
  427.     push    ax            ; save the buffer offset
  428.  
  429. ;;;;;;;;mov    cx,[DMABuffLength]    ; get the clearing length
  430. ;;;;;;;;mov    al,80h            ; PCM silent code
  431. ;;;;;;;;cld
  432. ;;;;;;;;rep stosb            ; flush the buffer length...
  433. ;;;;;;;;stosb                ; + 1
  434.  
  435.     mov    dx,es
  436.         pop     ax                      ; return dx:ax
  437.     jmp    short dmabdone
  438. ;
  439. dmabbad:
  440.     sub    ax,ax
  441.     cwd
  442. ;
  443. dmabdone:
  444.         pop     di
  445.     pop    es
  446.     pop    bp
  447.     ret
  448.  
  449. DMABuffer    endp
  450.  
  451.  
  452. ;   /*\
  453. ;---|*|---------------====< EnablePCMPlay() >====---------------
  454. ;---|*|
  455. ;---|*| Enabled the DAC hardware for polled output (no interrupts)
  456. ;---|*|
  457. ;---|*| Entry Conditions:
  458. ;---|*|     None
  459. ;---|*|
  460. ;---|*| Exit Conditions:
  461. ;---|*|     AX =  0 good start
  462. ;---|*|     AX = -1 not started, problem occured
  463. ;   \*/
  464.  
  465.     public    EnablePCMPlay
  466. EnablePCMPlay    proc
  467.     push    es
  468.  
  469.     mov    ax,wptr [TheSampleRate+0] ; Validate the sample rate
  470.     or    ax,wptr [TheSampleRate+2]
  471.     jz    enaPCMPlay_bad          ; zero sample rate, bomb out...
  472.  
  473.     call    FFAR ptr EnablePlaying      ; go for it...
  474.     mov    ax,0
  475.     jmp    short enaPCMPlay_exit
  476. ;
  477. enaPCMPlay_bad:
  478.     mov    ax,-1
  479. ;
  480. enaPCMPlay_exit:
  481.     pop    es
  482.         ret
  483.  
  484. EnablePCMPlay    endp
  485.  
  486.  
  487. ;   /*\
  488. ;---|*|---------------====< EnablePCMRecord() >====---------------
  489. ;---|*|
  490. ;---|*| Enabled the ADC hardware for polled input (no interrupts)
  491. ;---|*|
  492. ;---|*| Entry Conditions:
  493. ;---|*|     None
  494. ;---|*|
  495. ;---|*| Exit Conditions:
  496. ;---|*|     AX =  0 recording has started
  497. ;---|*|     AX = -1 recording did not start
  498. ;---|*|
  499. ;   \*/
  500.  
  501.     public    EnablePCMRecord
  502. EnablePCMRecord proc
  503.         push    es
  504.  
  505.     mov    ax,wptr [TheSampleRate+0] ; Validate the sample rate
  506.     or    ax,wptr [TheSampleRate+2]
  507.     jz    enaPCMRec_bad
  508.  
  509.     call    FFAR ptr EnableRecording  ; go for it...
  510.     mov    ax,0
  511.     jmp    short enaPCMRec_exit
  512. ;
  513. enaPCMRec_bad:
  514.     mov    ax,-1
  515. ;
  516. enaPCMRec_exit:
  517.     pop    es
  518.         ret
  519.  
  520. EnablePCMRecord endp
  521.  
  522.  
  523. ;   /*\
  524. ;---|*|------====< char far *FindDMABuffer(char far *,int ) >====------
  525. ;---|*|
  526. ;---|*| Finds the next 64k boundary starting with dParm1 address
  527. ;---|*|
  528. ;---|*| Entry Conditions:
  529. ;---|*|     dParm1 points to a buffer twice the size needed for the DMA
  530. ;---|*|     wParm2 is the size of the DMA buffer (4/8/16/32/64)
  531. ;---|*|
  532. ;---|*| Exit Conditions:
  533. ;---|*|     DX:AX = returns buffer pointer on a 64k boundary
  534. ;---|*|     DX:AX = 0 if boundary wraps beyond 1 meg.
  535. ;---|*|
  536. ;   \*/
  537.  
  538.     public    FindDMABuffer
  539. FindDMABuffer    proc
  540.     push    bp
  541.     mov    bp,sp
  542.  
  543.         mov     cx,wParm3               ; get the length
  544.     cmp    cx,64            ; 64k buffer requested?
  545.     ja    fdb_bad         ; too high, exit
  546.     jz    fdb_64k         ; yes, special case it...
  547.  
  548.     mov    ax,1024         ; calculate the length of the DMA buffer
  549.     mul    cx
  550.     mov    bx,ax            ; bx holds the length
  551.  
  552.     cmp    cx,4            ; is the buffer less than 4k
  553.     jl    fdb_doalign        ; yes, move on...
  554.  
  555.     mov    dx,0FFFh        ; precondition the offset
  556.     and    dx,dParm1        ; to align on a 4k page
  557.     xor    dParm1,dx
  558.  
  559.     mov    ax,00FFh        ; precondition the segment
  560.     and    ax,dParm1+2        ; to align on a 4k page
  561.     xor    dParm1+2,ax
  562.  
  563.     add    ax,dx
  564.     neg    ax            ; if not zero, move the offset to
  565.     sbb    ax,ax            ; the next 4k page
  566.     and    ax,1000h
  567.     add    dParm1,ax
  568.  
  569.         sbb     ax,ax
  570.     cwd                ; dx:ax = ffff if wrapped
  571.  
  572.     mov    cx,dParm1        ; get the new offset
  573.     neg    cx            ; if wrapped to zero, stay here...
  574.     sbb    cx,cx            ; cx = ffff if not zero
  575.     not    ax            ; ax = 0000 if wrapped
  576.     and    ax,cx            ; flush ax if offset is zero
  577.     and    dParm1,ax        ; adjust offset for special cases
  578.  
  579.     and    dx,1000h        ; move segment to the next 64k page
  580.     add    dParm1+2,dx
  581. ;
  582. fdb_doalign:
  583.     mov    dx,wptr dParm1+2
  584.     mov    ax,dx            ; accumulate the offset in ax
  585.     and    ax,0fffh        ; get the offset portion of the segment
  586.     and    dx,0f000h        ; make DX a 64k segment register
  587.         mov     cl,4
  588.     shl    ax,cl            ; make the segment an offset
  589.     add    ax,wptr dParm1+0    ; accumulate the rest of the offset
  590.     add    bx,ax            ; does the buffer cross a 64k boundary?
  591.     mov    cx,bx            ; (save w/o changing flags)
  592.  
  593.         sbb     bx,bx                   ; bx = ffff if crossed a 64k boundary
  594.     and    bx,cx            ; special case cx=0
  595.     neg    bx
  596.     cmc
  597.     sbb    bx,bx
  598.  
  599.         and     ax,bx                   ; clear ax if crossed
  600.     not    bx            ; bx = ffff if crossed, 0000 if not
  601.     and    bx,1000h
  602.     add    dx,bx            ; advance dx if we crossed a 64k boundary
  603.         pop     bp
  604.         ret
  605. ;
  606. fdb_bad:
  607.     sub    ax,ax
  608.     cwd
  609.         pop     bp
  610.         ret
  611. ;
  612. fdb_64k:
  613.     mov    dx,wptr dParm1+2    ; get the segment
  614.         sub     ax,ax                   ; offset is zero
  615.     and    dx,0f000h        ; find the next segment
  616.     add    dx,1000h        ; move to next segment
  617.     jc    fdb_bad         ; if does wraps past 1 meg, flush it...
  618.     pop    bp
  619.     ret
  620.  
  621. FindDMABuffer   endp
  622.  
  623. endif    ; PCMOBJ
  624. if MISC1OBJ
  625.  
  626. ;
  627. ;   /*\
  628. ;---|*|---------------====< InitMVSound() >====---------------
  629. ;---|*|
  630. ;---|*| Initializes this body of code. It will try to find the int 2F DOS
  631. ;---|*| interface to the MVPROAS device. Once found, the new state table
  632. ;---|*| pointer will be loaded.
  633. ;---|*|
  634. ;---|*| Entry Conditions:
  635. ;---|*|     None
  636. ;---|*|
  637. ;---|*| Exit Conditions:
  638. ;---|*|     DX:AX point to the state table
  639. ;   \*/
  640.  
  641.     public    InitMVSound
  642. InitMVSound    proc
  643.     push    es
  644.     push    di
  645.     mov    ax,ds
  646.     mov    es,ax
  647. ;
  648. ; find the hardware. Should be installed for this to run
  649. ;
  650.     call    MVInitStatePtr        ; initialize the state table ptr
  651.  
  652.     cmp    _MVHWVersionBits,-1    ; initialized yet?
  653.     jnz    @F            ; yes, continue on...
  654.     mov    ax,USE_ACTIVE_ADDR    ; pass in the base address
  655.     push    ax
  656.     call    mvGetHWVersion        ; no, checkout the hardware
  657.     pop    ax
  658.     ;
  659.     @@:
  660.     mov    ax,wptr [mvhwShadowPointer+0]
  661.     mov    dx,wptr [mvhwShadowPointer+2]
  662.  
  663.     pop    di
  664.     pop    es
  665.     ret
  666.  
  667. InitMVSound    endp
  668. ;
  669. endif    ; MISC1OBJ
  670. if    PCMOBJ
  671. ;
  672. ;   /*\
  673. ;---|*|---------------====< InitPCM() >====---------------
  674. ;---|*|
  675. ;---|*| Initializes the PCM code
  676. ;---|*|
  677. ;---|*| Entry Conditions:
  678. ;---|*|     None
  679. ;---|*|
  680. ;---|*| Exit Conditions:
  681. ;---|*|     AX =  Version of this Code
  682. ;   \*/
  683.  
  684.     public    InitPCM
  685. InitPCM proc
  686.     push    es
  687.  
  688.     mov    [TypeOfSetup],polledmask    ; flushes both interrupts
  689.                         ; for upcoming calls
  690.     mov    al,TheDMAChannel        ; initialize the DMA now...
  691.     cbw
  692.     push    ax
  693.     call    FFAR ptr SelectDMA
  694.     pop    ax
  695.  
  696.     mov    al,TheIRQChannel        ; initialize the IRQ now...
  697.     cbw
  698.     push    ax
  699.     call    FFAR ptr SelectIRQ        ; also removes the IRQ
  700.     pop    ax
  701.  
  702.         call    FFAR ptr StopPCM                ; kill the Audio Spectrum board
  703.  
  704.     mov    dx,INTRCTLRST            ; flush any pending PCM irq
  705.     xor    dx,[_MVTranslateCode]        ; xlate the board address
  706.     out    dx,al
  707.  
  708.     sub    ax,ax
  709.     mov    [TypeOfSetup],al        ; unknown type
  710.  
  711.     mov    wptr [UserRoutine+0],ax
  712.     mov    wptr [UserRoutine+2],ax
  713.  
  714.     mov    wptr [LinearPtr+0],ax
  715.     mov    wptr [LinearPtr+2],ax
  716.     mov    wptr [SegmentedPtr+0],ax
  717.         mov     wptr [SegmentedPtr+2],ax
  718.  
  719.     mov    wptr [DMABuffLength],ax
  720.  
  721.     not    al
  722.     mov    [StereoMono],al         ; mono
  723.  
  724.     mov    ax,11025
  725.     cwd
  726.  
  727.     call    FFAR ptr _calcsamplerate    ; setup the default rate
  728.     mov    wptr [TheSampleRate+0],ax
  729.     mov    wptr [TheSampleRate+2],dx
  730.  
  731.     mov    ax,0003h            ; for compatibility, version 00.03
  732.  
  733.     pop    es
  734.     ret
  735.  
  736. InitPCM endp
  737. ;
  738. endif    ; PCMOBJ
  739. if PCMOBJ
  740. ;
  741. ;
  742. ;   /*\
  743. ;---|*|---------------====< PausePCM >====---------------
  744. ;---|*|
  745. ;---|*| Turn off the h/w timer enables to effectively stop pcm temporarily.
  746. ;---|*|
  747. ;---|*| Entry Conditions:
  748. ;---|*|     None
  749. ;---|*|
  750. ;---|*| Exit Conditions:
  751. ;---|*|     Nothing
  752. ;---|*|
  753. ;   \*/
  754. ;
  755.     public    PausePCM
  756. PausePCM    proc
  757.     push    es
  758.     push    di
  759. ;
  760. ; Setup the audio filter sample bits
  761. ;
  762.     les    di,[mvhwShadowPointer]
  763.         mov     dx,AUDIOFILT
  764.     xor    dx,[_MVTranslateCode]       ; xlate the board address
  765.  
  766.         disable
  767.  
  768.         mov     al,es:[di._audiofilt]
  769.     and    al,not bFIsrate        ; flush the enable bits
  770.     mov    es:[di._audiofilt],al
  771.     out    dx,al
  772.  
  773.     enable
  774.  
  775.         pop     di
  776.     pop    es
  777.     ret
  778.  
  779. PausePCM    endp
  780.  
  781. ;
  782. ;   /*\
  783. ;---|*|---------------====< PCMInfo ( long, int, int, int ) >====---------------
  784. ;---|*|
  785. ;---|*| Selects xfer rate & stereo/mono
  786. ;---|*|
  787. ;---|*| Entry Conditions:
  788. ;---|*|     Parm #1 (wParm1, wParm2) is the rate
  789. ;---|*|     Parm #2 (wParm3)         is the stereo(1) or mono (0)
  790. ;---|*|     Parm #3 (wParm4)         is the compression flag
  791. ;---|*|     Parm #4 (wParm5)         is the data size (8/12/16 bits per sample)
  792. ;---|*|
  793. ;---|*| Exit Conditions:
  794. ;---|*|     AX =  0, good data
  795. ;---|*|     AX = -1, bum transfer rate
  796. ;---|*|
  797. ;   \*/
  798.  
  799.     public    PCMInfo
  800. PCMInfo     proc
  801.     push    bp
  802.     mov    bp,sp
  803.  
  804.     mov    al,wParm4+2        ; get the data size
  805.     cbw
  806.     cmp    al,8            ; 8 bit channel?
  807.     jz    @F
  808.  
  809.         inc     ah
  810.     cmp    al,12            ; 12 bit channel
  811.     jz    @F
  812.  
  813.     inc    ah
  814.     cmp    al,16            ; 16 bit channel?
  815.     jnz    pcinf_bad        ; no, bomb out...
  816.     ;
  817.     @@:
  818.     mov    [SampleSize],ah
  819.  
  820.         mov     cx,wParm3               ; get the stereo flag
  821.     shr    cx,1
  822.     jnz    pcinf_bad        ; exit bad if not zero
  823.  
  824.     cmc                ; set for mono, cleared for stereo
  825.     sbb    cx,cx            ; make a full bit mask
  826.     mov    [StereoMono],cl     ; save only valid values
  827.  
  828.         mov     ax,dParm1+0             ; get the sample rate
  829.     mov    dx,dParm1+2
  830.  
  831.     or    cx,cx            ; is it mono?
  832.     jnz    @F            ; yes, skip the doubling
  833.     shl    ax,1            ; no, stereo, so double the sample rate
  834.     adc    dx,dx
  835.     ;
  836.     @@:
  837.     call    FFAR ptr _calcsamplerate
  838.     jc    pcinf_bad
  839.     mov    wptr [TheSampleRate+0],ax
  840.     mov    wptr [TheSampleRate+2],dx
  841.  
  842.     sub    ax,ax
  843.     jmp    short pcinf_exit
  844. ;
  845. pcinf_bad:
  846.     mov    ax,-1
  847. ;
  848. pcinf_exit:
  849.         pop     bp
  850.     ret
  851.  
  852. PCMInfo     endp
  853. ;
  854. ;
  855. ;   /*\
  856. ;---|*|---------------====< PCMPlay() >====---------------
  857. ;---|*|
  858. ;---|*| Starts the DMA feeding the DAC
  859. ;---|*|
  860. ;---|*| Entry Conditions:
  861. ;---|*|     None
  862. ;---|*|
  863. ;---|*| Exit Conditions:
  864. ;---|*|     AX =  0 good start
  865. ;---|*|     AX = -1 not started, problem occured
  866. ;   \*/
  867.  
  868.     public    PCMPlay
  869. PCMPlay proc
  870.     push    es
  871.  
  872.     les    ax,LinearPtr          ; Validate the buffer pointer
  873.     mov    bx,es
  874.     or    ax,bx
  875.     jz    PCMPlay_bad
  876.  
  877.     mov    ax,[DMABuffLength]      ; Validate the buffer count
  878.     or    ax,ax
  879.     jz    PCMPlay_bad
  880.  
  881.     mov    ax,wptr [TheSampleRate+0] ; Validate the sample rate
  882.     or    ax,wptr [TheSampleRate+2]
  883.     jz    PCMPlay_bad          ; zero sample rate, bomb out...
  884.  
  885.     call    FFAR ptr StartPlaying      ; go for it...
  886.     sub    ax,ax
  887.     jmp    short PCMPlay_exit
  888. ;
  889. PCMPlay_bad:
  890.     mov    ax,-1
  891. ;
  892. PCMPlay_exit:
  893.     pop    es
  894.         ret
  895.  
  896. PCMPlay endp
  897. ;
  898. ;
  899. ;   /*\
  900. ;---|*|---------------====< PCMRecord() >====---------------
  901. ;---|*|
  902. ;---|*| Starts the DMA reading the ADC
  903. ;---|*|
  904. ;---|*| Entry Conditions:
  905. ;---|*|     None
  906. ;---|*|
  907. ;---|*| Exit Conditions:
  908. ;---|*|     AX =  0 recording has started
  909. ;---|*|     AX = -1 recording did not start
  910. ;---|*|
  911. ;   \*/
  912.  
  913.     public    PCMRecord
  914. PCMRecord proc
  915.         push    es
  916.  
  917.     les    ax,LinearPtr          ; Validate the buffer pointer
  918.     mov    bx,es
  919.     or    ax,bx
  920.     jz    PCMRec_bad
  921.  
  922.     mov    ax,[DMABuffLength]      ; Validate the buffer count
  923.     or    ax,ax
  924.     jz    PCMRec_bad
  925.  
  926.     mov    ax,wptr [TheSampleRate+0] ; Validate the sample rate
  927.     or    ax,wptr [TheSampleRate+2]
  928.     jz    PCMRec_bad
  929.  
  930.     call    FFAR ptr StartRecording   ; go for it...
  931.     mov    ax,0
  932.     jmp    short PCMRec_exit
  933. ;
  934. PCMRec_bad:
  935.     mov    ax,-1
  936. ;
  937. PCMRec_exit:
  938.     pop    es
  939.         ret
  940.  
  941. PCMRecord    endp
  942. ;
  943. ;
  944. ;   /*\
  945. ;---|*|---------------====< RemovePCM () >====---------------
  946. ;---|*|
  947. ;---|*| Remove our code from the system
  948. ;---|*|
  949. ;---|*| Entry Conditions:
  950. ;---|*|     None
  951. ;---|*|
  952. ;---|*| Exit Conditions:
  953. ;---|*|     None
  954. ;   \*/
  955.  
  956.     public    RemovePCM
  957. RemovePCM proc
  958.  
  959.     call    FFAR ptr StopPCM        ; kill the Audio Spectrum board
  960.  
  961.         mov     dx,INTRCTLRST                   ; flush any pending PCM irq
  962.         xor     dx,[_MVTranslateCode]           ; xlate the board address
  963.         out     dx,al
  964.  
  965.     call    FFAR ptr _unloadirqvector    ; restore the original vector
  966.  
  967.         ret
  968.  
  969. RemovePCM endp
  970. ;
  971. ;
  972. ;   /*\
  973. ;---|*|---------------====< ResumePCM >====---------------
  974. ;---|*|
  975. ;---|*| Turn on the h/w from making interrupt and DMA requests. This assumes
  976. ;---|*| the hardware has already been setup and is ready to go...
  977. ;---|*|
  978. ;---|*| Entry Conditions:
  979. ;---|*|     None
  980. ;---|*|
  981. ;---|*| Exit Conditions:
  982. ;---|*|     Nothing
  983. ;---|*|
  984. ;   \*/
  985. ;
  986.     public    ResumePCM
  987. ResumePCM    proc
  988.     push    es
  989.     push    di
  990. ;
  991. ; Setup the audio filter sample bits
  992. ;
  993.     les    di,[mvhwShadowPointer]
  994.     call    FFAR ptr _ASloadtimer0
  995.  
  996.         disable
  997.  
  998.         mov     dx,AUDIOFILT
  999.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1000.     mov    al,es:[di._audiofilt]
  1001.     or    al,bFIsrate        ; enable sample rate and buffer timers
  1002.     mov    es:[di._audiofilt],al
  1003.     out    dx,al
  1004.  
  1005.     enable
  1006.  
  1007.         pop     di
  1008.     pop    es
  1009.     ret
  1010.  
  1011. ResumePCM       endp
  1012. ;
  1013. ;
  1014. ;
  1015. ;   /*\
  1016. ;---|*|---------------====< SelectDMA( int ) >====---------------
  1017. ;---|*|
  1018. ;---|*| Selects the DMA channel 0 - 7, excluding 4
  1019. ;---|*|
  1020. ;---|*| Entry Conditions:
  1021. ;---|*|     wParm1 points to DMA number (0, 1, 2, 3, 5, 6, 7 )
  1022. ;---|*|
  1023. ;---|*| Exit Conditions:
  1024. ;---|*|     AX =  0, good buffer, all okay
  1025. ;---|*|     AX = -1, good buffer, all okay
  1026. ;---|*|
  1027. ;   \*/
  1028.  
  1029.         public  SelectDMA
  1030. SelectDMA    proc
  1031.     push    bp
  1032.     mov    bp,sp
  1033.  
  1034.         mov     ax,wParm1               ; get the DMA #
  1035.  
  1036.     and    ax,0111b        ; save the channels
  1037.  
  1038.         mov     bx,ax                   ; get some of the I/O addreses
  1039.     shl    bx,1            ; into DX
  1040.     jnz    seldma_02        ; not channel 0, go use it...
  1041.     push    sp            ; 8088/86 class machine?
  1042.     pop    cx
  1043.     cmp    cx,sp
  1044.     jnz    seldma_bad        ; yes, can't do channel 0 dma
  1045.     ;
  1046.     seldma_02:
  1047.         mov     dx,cs:[dmatable+bx]
  1048.     or    dx,dx            ; valid entry?
  1049.     jz    seldma_bad        ; no, bomb out...
  1050.  
  1051.         mov     TheDMAChannel,al        ; select the channel.
  1052.     mov    bptr OurDMAPageReg,dh    ; ...the page register,
  1053.     mov    bptr OurDMAddress,dl    ; ...the address register,
  1054.  
  1055.     lea    bx,DMA1AddrTable    ; get the DMA channel addresses
  1056.     cmp    al,4
  1057.     jl    seldma_05
  1058.     lea    bx,DMA2AddrTable    ; get the DMA channel addresses
  1059.     sub    al,4            ; make it zero based
  1060.     ;
  1061.     seldma_05:
  1062.     mov    [bx._dmach],al        ; save the adjusted dma channel #
  1063.     mov    [DMAPointer],bx     ; save the pointer to all DMA addrs
  1064.     sub    ax,ax
  1065.     pop    bp
  1066.     ret
  1067. ;
  1068. seldma_bad:
  1069.     mov    ax,-1
  1070.     pop    bp
  1071.     ret
  1072. ;
  1073. ; dma channels, etc
  1074. ;
  1075. dmatable    label    word
  1076.     dw    (CH0PAGEREG SHL 8) + DMAC0ADDR
  1077.         dw      (CH1PAGEREG SHL 8) + DMAC1ADDR
  1078.     dw    (CH2PAGEREG SHL 8) + DMAC2ADDR
  1079.     dw    (CH3PAGEREG SHL 8) + DMAC3ADDR
  1080.         dw      0
  1081.     dw    (CH5PAGEREG SHL 8) + DMA2C5ADDR
  1082.     dw    (CH6PAGEREG SHL 8) + DMA2C6ADDR
  1083.     dw    (CH7PAGEREG SHL 8) + DMA2C7ADDR
  1084.  
  1085. SelectDMA       endp
  1086.  
  1087. endif    ; PCMOBJ
  1088. if MISC2OBJ
  1089.  
  1090. ;   /*\
  1091. ;---|*|---------------====< SelectIRQ( int ) >====---------------
  1092. ;---|*|
  1093. ;---|*| Selects the IRQ line for DMA control
  1094. ;---|*|
  1095. ;---|*| Entry Conditions:
  1096. ;---|*|     wParm1 points to IRQ number (3,5,6,7)
  1097. ;---|*|
  1098. ;---|*| Exit Conditions:
  1099. ;---|*|     AX =  0, good buffer, all okay
  1100. ;---|*|     AX = -1, bad IRQ #
  1101. ;---|*|
  1102. ;   \*/
  1103.  
  1104.         public  SelectIRQ
  1105. SelectIRQ    proc
  1106.     push    bp
  1107.     mov    bp,sp
  1108.  
  1109.     call    FFAR ptr _unloadirqvector ; attempt to restore original vector
  1110.  
  1111.     sub    ax,ax            ; flush ax for a bad return
  1112.  
  1113.     mov    cx,wParm1        ; get the irq # (2-7,10-12,14-15)
  1114.     and    cl,0fh            ; save only the valid bits
  1115.     mov    bx,01
  1116.     shl    bx,cl
  1117.  
  1118.     and    bx,1001110010111100b    ; save the mask bit only if the irq
  1119.         jz      seirqbad                ; is a valid selection
  1120.  
  1121.     mov    TheIRQChannel,cl    ; save the channel number
  1122.  
  1123.     cmp    cl,8            ; 2nd interrupt controller?
  1124.     jb    @F            ; no, skip
  1125.     xchg    bh,bl
  1126.     ;
  1127.     @@:
  1128.     mov    TheIRQMask,bl
  1129.     call    FFAR ptr _loadirqvector ; load the new vector
  1130.     mov    ax,1
  1131. ;
  1132. seirqbad:
  1133.     dec    ax
  1134.     pop    bp
  1135.     ret
  1136.  
  1137. SelectIRQ       endp
  1138. ;
  1139. endif    ; MISC2OBJ
  1140. if PCMOBJ
  1141.  
  1142. ;
  1143. ;   /*\
  1144. ;---|*|--------------------====< void StopPCM() >====--------------------
  1145. ;---|*|
  1146. ;---|*| Turn off the PCM timers, interrupts, and state machine.
  1147. ;---|*|
  1148. ;---|*| Entry Conditions:
  1149. ;---|*|
  1150. ;---|*| Exit  Conditions:
  1151. ;---|*|
  1152. ;---|*|
  1153. ;   \*/
  1154.  
  1155.     public    StopPCM
  1156. StopPCM proc
  1157.     push    es
  1158.     push    di
  1159.     les    di,[mvhwShadowPointer]
  1160. ;
  1161. ; clear the audio filter sample bits
  1162. ;
  1163.     mov    dx,AUDIOFILT
  1164.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1165.     disable             ; drop dead...
  1166.     mov    al,es:[di._audiofilt]    ; get the state
  1167.     and    al,not (bFIsrate+bFIsbuff) ; flush the sample timer bits
  1168.     mov    es:[di._audiofilt],al    ; save the new state
  1169.     out    dx,al
  1170. ;
  1171. ; clear the PCM enable bit
  1172. ;
  1173.     mov    al,es:[di._crosschannel]; get the current cross channel
  1174.     and    al,not bCCenapcm    ; clear the PCM enable bit
  1175.     or    al,bCCdac
  1176.         mov     dx,CROSSCHANNEL
  1177.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1178.     out    dx,al            ; end to the hardware
  1179.     mov    es:[di._crosschannel],al
  1180. ;
  1181. ; disable the 16 bit stuff
  1182. ;
  1183.     test    [_MVHWVersionBits],bMV101  ; 101 chip?
  1184.     jz    stpc02               ; no, don't touch this...
  1185.     mov    dx,SYSCONFIG2
  1186.     xor    dx,[_MVTranslateCode]       ; xlate the board address
  1187.     in    al,dx
  1188.     and    al,not bSC216bit+bSC212bit ; flush the 16 bit stuff
  1189.     out    dx,al
  1190.     ;
  1191.     stpc02:
  1192. ;
  1193. ; clear the appropriate Interrupt Control Register bit
  1194. ;
  1195.     mov    ah,TypeOfSetup
  1196.     and    ah,bICsamprate+bICsampbuff
  1197.     not    ah
  1198.     mov    dx,INTRCTLR
  1199.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1200.     in    al,dx
  1201.     and    al,ah            ; kill sample timer interrupts
  1202.     out    dx,al
  1203.     mov    es:[di._intrctlr],al
  1204. ;
  1205. ; clear the system interrupt mask only if no other ints are used
  1206. ;
  1207.     test    al,fICintmaskbits XOR (bICsamprate+bICsampbuff)
  1208.     jnz    stpc10
  1209. ;
  1210. ; select the correct IRQ controller, then mask it...
  1211. ;
  1212.     cmp    TheIRQChannel,2     ; Chained IRQ channel?
  1213.     jz    stpc10            ; yes, leave it open...
  1214.  
  1215.         mov     dx,IRQ1MASKREG
  1216.     cmp    TheIRQChannel,8     ; 2nd IRQ controller?
  1217.     jl    stpc05
  1218.     mov    dl,IRQ2MASKREG
  1219.     ;
  1220.     stpc05:
  1221.     in    al,dx
  1222.     or    al,[TheIRQMask]
  1223.     out    dx,al
  1224.     enable                ; start again...
  1225. ;
  1226. stpc10:
  1227.     call    FFAR ptr KillDMA    ; stop the DMA too...
  1228.  
  1229.     mov    [StatusWord],0        ; inactive, available
  1230.  
  1231.     pop    di
  1232.     pop    es
  1233.     ret
  1234.  
  1235. StopPCM endp
  1236.  
  1237. ;
  1238. ;   /*\
  1239. ;---|*|---------------====< UserFunc((*long)()) >====---------------
  1240. ;---|*|
  1241. ;---|*| Call back routine when Half way buffer is full/empty.
  1242. ;---|*|
  1243. ;---|*| Entry Conditions:
  1244. ;---|*|     dParm1 points to the user routine
  1245. ;---|*|
  1246. ;---|*| Exit Conditions:
  1247. ;---|*|     Nothing
  1248. ;---|*|
  1249. ;   \*/
  1250.  
  1251.     public    UserFunc
  1252. UserFunc proc
  1253.     push    bp
  1254.     mov    bp,sp
  1255.  
  1256.         push    es
  1257.  
  1258.     les    ax,dParm1        ; get the routine
  1259.     mov    dx,es
  1260.     or    dx,ax
  1261.     jz    usfu_bad
  1262.  
  1263.     mov    wptr [UserRoutine+0],ax
  1264.     mov    wptr [UserRoutine+2],es
  1265. ;
  1266. usfu_bad:
  1267.     pop    es
  1268.     pop    bp
  1269.     ret
  1270.  
  1271. UserFunc endp
  1272.  
  1273. endif    ; PCMOBJ
  1274.  
  1275. ;
  1276. ;
  1277. ;----------------------------========================--------------------------
  1278. ;----------------------------========================--------------------------
  1279. ;----------------------------========================--------------------------
  1280. ;
  1281. ;
  1282. ;            PPPPPPPP      CCCCCC   MMM     MMM
  1283. ;            PPPPPPPP     CCCCCCC   MMMM    MMMM
  1284. ;            PPP   PPP   CCC        MMMMM   MMMMM
  1285. ;            PPP   PPP   CCC        MMMMMM MMMMMM
  1286. ;            PPPPPPPP    CCC        MMM MMMMM MMM
  1287. ;            PPPPPPPP    CCC        MMM  MMM  MMM
  1288. ;            PPP        CCC        MMM   M     MMM
  1289. ;            PPP        CCC        MMM     MMM
  1290. ;            PPP         CCCCCCC   MMM     MMM
  1291. ;            PPP          CCCCCC   MMM     MMM
  1292. ;
  1293. ;     rrrrr      oooo     uu  uu  tttttt  iiiiii  nn  nn   eeeee   sssss
  1294. ;     rr  rr  oo  oo  uu  uu    tt       ii     nnn nn  ee     ss
  1295. ;     rrrrrr  oo  oo  uu  uu    tt       ii     nnnnnn  eeeeee   ssss
  1296. ;     rr rr     oo  oo  uu  uu    tt       ii     nn nnn  ee         ss
  1297. ;     rr  rr   oooo      uuuuuu   tt     iiiiii  nn  nn   eeeee  sssss
  1298. ;
  1299. ;
  1300. ;
  1301. ;----------------------------========================--------------------------
  1302. ;----------------------------========================--------------------------
  1303. ;----------------------------========================--------------------------
  1304.  
  1305. if PCMOBJ
  1306.  
  1307. ;
  1308. ;----------------------------====< _ASloadtimer0 >====-------------------------
  1309. ;
  1310. ;
  1311. ; Setup the Sample Timer (T0 & square wave output)
  1312. ;
  1313. ;   Entry Conditions:
  1314. ;    ES:DI point to the state table.
  1315. ;   Exit Conditions:
  1316. ;    The timer is loaded with the new sample rate
  1317. ;
  1318.     public    _ASloadtimer0
  1319. _ASloadtimer0    proc
  1320.  
  1321.         mov     al,00110110b            ; 36h Timer 0 & square wave
  1322.     mov    dx,TMRCTLR
  1323.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1324.  
  1325.     pushf
  1326.     cli
  1327.  
  1328.     out    dx,al            ; setup the mode, etc
  1329.         mov     es:[di._tmrctlr],al
  1330.  
  1331.     mov    ax,es:[di._samplerate]    ; pre-calculated & saved in prior code
  1332.     mov    dx,SAMPLERATE
  1333.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1334.     out    dx,al            ; output the timer value
  1335.  
  1336.         pause
  1337.  
  1338.         xchg    ah,al
  1339.     out    dx,al
  1340.  
  1341.         popf
  1342.     ret
  1343.  
  1344. _ASloadtimer0   endp
  1345.  
  1346. ;
  1347. ;----------------------------====< _ASloadtimer1 >====-------------------------
  1348. ;
  1349.         public  _ASloadtimer1
  1350. _ASloadtimer1   proc
  1351.     push    es
  1352.     push    di
  1353.     les    di,[mvhwShadowPointer]
  1354.  
  1355.         push    dx                      ; do not disturb any register
  1356.     push    ax
  1357.  
  1358.         mov     al,01110100b            ; 74h Timer 1 & rate generator
  1359.     mov    dx,TMRCTLR
  1360.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1361.  
  1362.         disable
  1363.  
  1364.         out     dx,al
  1365.     mov    es:[di._tmrctlr],al    ; local timer control register
  1366.  
  1367.     pop    ax
  1368.  
  1369.         mov     dx,SAMPLECNT
  1370.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1371.     mov    es:[di._samplecnt],ax
  1372.  
  1373.         out     dx,al
  1374.         pause
  1375.     xchg    ah,al
  1376.     out    dx,al
  1377.  
  1378.     enable
  1379.  
  1380.     xchg    ah,al
  1381.  
  1382.     pop    dx
  1383.     pop    di
  1384.     pop    es
  1385.     ret
  1386.  
  1387. _ASloadtimer1    endp
  1388. ;
  1389. ;
  1390. ;--------------------------====< _calcsamplerate >====-------------------------
  1391. ;
  1392. ;  Calculate the H/W timer value (internal routine)
  1393. ;
  1394. ; Entry Conditions:
  1395. ;    DX:AX hold the users requested sample rate
  1396. ;
  1397. ; Exit Conditions:
  1398. ;    carry SET if bad value
  1399. ;    No registers modified
  1400. ;
  1401. ;
  1402.     public    _calcsamplerate
  1403. _calcsamplerate proc
  1404.     push    es
  1405.     push    di
  1406.     les    di,[mvhwShadowPointer]
  1407.  
  1408.     push    ax
  1409.     push    bx
  1410.     push    cx
  1411.     push    dx
  1412. ;
  1413. ; make sure sample rate does not exceed 88200
  1414. ;
  1415.         mov     cx,ax                   ; do 32 bit subtraction
  1416.     sub    cx,05888H+1        ; 157C0 is decimal 88200
  1417.     mov    cx,dx            ; too high?
  1418.     sbb    cx,00001H        ;  over 88200 khz is bad
  1419.     jnc    CaSaRa_bad        ; bomb out greater than 88200
  1420. ;
  1421. ; load 1193180 in bx:cx for 32x32 bit division
  1422. ;
  1423.     mov    bx,0012h
  1424.     mov    cx,34dch        ; load bx:cx with 1193180
  1425.  
  1426.     xchg    bx,dx            ; dx:ax = 1193180
  1427.     xchg    cx,ax            ; bx:cx = sample rate
  1428. ;
  1429. ; since we don't have 32x32 bit division, we'll cheat here. No great loss.
  1430. ;
  1431.     or    bx,bx            ; is value over 64k?
  1432.     jz    @F            ; no, continue on...
  1433.     shr    bx,1            ; yes, divide all by 2
  1434.     rcr    cx,1            ; to allow division of 32x16 bits
  1435.     shr    dx,1
  1436.     rcr    ax,1
  1437. ;
  1438. @@:
  1439.     div    cx
  1440.     mov    es:[di._samplerate],ax    ; save just the low order
  1441.     clc
  1442.     jmp    short CaSaRa_exit
  1443. ;
  1444. CaSaRa_bad:
  1445.     stc
  1446. ;
  1447. CaSaRa_exit:
  1448.     pop    dx
  1449.     pop    cx
  1450.     pop    bx
  1451.     pop    ax
  1452.  
  1453.         pop     di
  1454.     pop    es
  1455.     ret
  1456.  
  1457. _calcsamplerate endp
  1458. ;
  1459. ;
  1460. ;----------------------------====< EnableRecording >====-----------------------
  1461. ;
  1462.     public    EnableRecording
  1463. EnableRecording  proc
  1464. ;
  1465. ; Save the type of setup. It contains the interrupt masks needed
  1466. ;
  1467.     mov    [TypeOfSetup],POLLEDINPUT
  1468.     mov    [PCMDirection],0    ; bit 6 is cleared (DAC enable)
  1469. ;
  1470. ; enable the onboard sampling timers, disable interrupts
  1471. ;
  1472.     call    FFAR ptr SetupPCMPolledIO ; Setup the MV Hardware
  1473.     mov    StatusWord,2        ; set the global status word
  1474.         ret
  1475.  
  1476. EnableRecording  endp
  1477. ;
  1478. ;
  1479. ;----------------------------====< EnablePlaying >====-------------------------
  1480. ;
  1481.     public    EnablePlaying
  1482. EnablePlaying    proc
  1483. ;
  1484. ; Save the type of setup. It contains the interrupt masks needed
  1485. ;
  1486.     mov    [TypeOfSetup],POLLEDOUTPUT
  1487.         mov     [PCMDirection],bCCdac   ; bit d6 of interrupt control register
  1488. ;
  1489. ; enable the onboard sampling timers, etc.
  1490. ;
  1491.     call    FFAR ptr SetupPCMPolledIO ; Setup the MV Hardware
  1492.     mov    StatusWord,1        ; set the global status word
  1493.  
  1494.         ret
  1495.  
  1496. EnablePlaying     endp
  1497. ;
  1498. endif    ; PCMOBJ
  1499. if MISC2OBJ
  1500. ;
  1501. ;---------------------------====< _getirqoffset >====--------------------------
  1502. ;
  1503. ; takes the IRQ # & converts to offset in vector table
  1504. ;
  1505. ;
  1506.     public    _getirqoffset
  1507. _getirqoffset   proc
  1508.         sub     bh,bh
  1509.     shl    bx,1
  1510.     mov    bx,cs:[irqoffsets+bx]
  1511.     ret
  1512.  
  1513. irqoffsets    label    word
  1514.     dw    (8+0)*4         ; IRQ 0 clock timer
  1515.     dw    (8+1)*4         ; IRQ 1 keyboard
  1516.     dw    (8+2)*4         ; IRQ 2 available
  1517.     dw    (8+3)*4         ; IRQ 3 COM2
  1518.     dw    (8+4)*4         ; IRQ 4 COM1
  1519.     dw    (8+5)*4         ; IRQ 5 available
  1520.     dw    (8+6)*4         ; IRQ 6 floppy controller
  1521.     dw    (8+7)*4         ; IRQ 7 LPT
  1522.     dw    (70h+0)*4        ; IRQ 8 real time clock
  1523.     dw    (70h+1)*4        ; IRQ 9 Re-Directed IRQ2
  1524.     dw    (70h+2)*4        ; IRQ a available
  1525.     dw    (70h+3)*4        ; IRQ b available
  1526.     dw    (70h+4)*4        ; IRQ c available
  1527.     dw    (70h+5)*4        ; IRQ d coprocessor
  1528.     dw    (70h+6)*4        ; IRQ e Hard Disk
  1529.     dw    (70h+7)*4        ; IRQ f available
  1530.  
  1531. _getirqoffset   endp
  1532. ;
  1533. endif    ; MISC2OBJ
  1534. if PCMOBJ
  1535. ;
  1536. ;------------------------------====< KillDMA >====-----------------------------
  1537. ;
  1538. ; KillDMA  -- flush our settings
  1539. ;
  1540. ; Entry Conditions:
  1541. ;
  1542. KillDMA proc
  1543.     push    es
  1544.     push    di
  1545.  
  1546.         cmp     StatusWord,0            ; is there any activity?
  1547.     jz    kidm_none
  1548.  
  1549.     mov    di,[DMAPointer]     ; get the DMA pointer
  1550.         sub     dx,dx                   ; clear out the high byte
  1551. ;
  1552. ; mask out the DMA to stop it
  1553. ;
  1554.     disable
  1555.     mov    al,[di._dmach]        ; get the adjusted dma channel #
  1556.         or      al,0100b                ; disable the DMA
  1557.     mov    dl,[di._dmawrsmr]
  1558.     out    dx,al
  1559. ;
  1560. ; remove control on the DRQ line
  1561. ;
  1562.         les     di,[mvhwShadowPointer]
  1563.  
  1564.         mov     al,es:[di._crosschannel]; get the state
  1565.         mov     dx,CROSSCHANNEL
  1566.         xor     dx,[_MVTranslateCode]           ; xlate the board address
  1567.     and    al,not bCCdrq        ; clear the DRQ bit
  1568.     out    dx,al
  1569.  
  1570.         mov     es:[di._crosschannel],al; and save the new state
  1571.     enable
  1572. ;
  1573. kidm_none:
  1574.     pop    di
  1575.     pop    es
  1576.     ret
  1577.  
  1578. KillDMA endp
  1579. ;
  1580. endif    ; PCMOBJ
  1581. if PCMOBJ
  1582. ;
  1583. ;------------------------------====< LoadDMA >====-----------------------------
  1584. ;
  1585. ; LoadDMA  -- Load the DMA controller to read/write data to the MV board
  1586. ;
  1587. ; Entry Conditions:
  1588. ;
  1589. ;
  1590.     public    LoadDMA
  1591. LoadDMA proc
  1592.     push    es
  1593.     push    di
  1594.     push    si
  1595.  
  1596.         les     di,[mvhwShadowPointer]
  1597.  
  1598.     mov    si,[DMAPointer]     ; point to the DMA controller table
  1599.     sub    dx,dx            ; clear out the high byte
  1600. ;
  1601. ; kill the dma until all programming is done
  1602. ;
  1603.     mov    al,[si._dmach]        ; get the adjusted dma channel #
  1604.         or      al,0100b                ; causes all DMA to be suspended
  1605.     mov    dl,[si._dmawrsmr]
  1606.     out    dx,al
  1607. ;
  1608. ; program the mode
  1609. ;
  1610.         mov     al,[TheDMAmode]         ; get the app's desired mode
  1611.     or    al,[si._dmach]        ; merge the adjusted dma channel #
  1612.     mov    dl,[si._dmawrmode]
  1613.         out     dx,al
  1614. ;
  1615. ; adjust the address for a 16 bit channel
  1616. ;
  1617.     mov    ax,wptr [LinearPtr+2]    ; get the page #
  1618. ;
  1619. ; setup the page register
  1620. ;
  1621.     mov    dx,[OurDMAPageReg]
  1622.     out    dx,al
  1623.     mov    bl,al
  1624. ;
  1625. ; reset the flip-flop, then output the address, then count
  1626. ;
  1627.     mov    dl,[si._dmaclear]    ; dh is still clear...
  1628.         out     dx,al                   ; flush...
  1629.  
  1630.     mov    ax,wptr [LinearPtr+0]    ; get the low 16 bits
  1631.     cmp    si,offset DMA1AddrTable ; 1st DMA controller?
  1632.     jz    @F            ; yes, continue on...
  1633.     shr    bl,1            ; no, divide the buffer in half
  1634.     rcr    ax,1            ; by shifting 17 bits
  1635.     ;
  1636.     @@:
  1637.     mov    dx,[OurDMAddress]
  1638.     out    dx,al
  1639.     pause
  1640.     xchg    ah,al
  1641.     out    dx,al
  1642.  
  1643.     mov    ax,[DMABuffLength]
  1644.     cmp    si,offset DMA1AddrTable ; is this the 2nd dma controller?
  1645.     jz    lodma03         ; no, use the full length
  1646.     shr    ax,1
  1647.         inc     dx                      ; move to next port address
  1648.     ;
  1649.     lodma03:
  1650.     inc    dx            ; move to next port address
  1651.     out    dx,al
  1652.     pause
  1653.     xchg    ah,al
  1654.     out    dx,al
  1655. ;
  1656. ; before we enable the DMA, let's make sure the DRQ is controlled, not floating
  1657. ;
  1658.     mov    al,es:[di._crosschannel]; get the state
  1659.         mov     dx,CROSSCHANNEL
  1660.         xor     dx,[_MVTranslateCode]           ; xlate the board address
  1661.     or    al,bCCdrq        ; set the DRQ bit to control it
  1662.     out    dx,al
  1663.     mov    es:[di._crosschannel],al; and save the new state
  1664. ;
  1665. ; re-enable the dma now that all programming is done
  1666. ;
  1667.     mov    al,[si._dmach]        ; get the adjusted dma channel #
  1668.         sub     dx,dx                   ; clear dh
  1669.     mov    dl,[si._dmawrsmr]
  1670.     out    dx,al            ; & let'er loose (not moving though...)
  1671. ;
  1672. ; all done, return home...
  1673. ;
  1674.     pop    si
  1675.     pop    di
  1676.     pop    es
  1677.     ret
  1678.  
  1679. LoadDMA endp
  1680. ;
  1681. endif    ; PCMOBJ
  1682. if MISC2OBJ
  1683. ;
  1684. ;--------------------------====< _loadirqvector >====--------------------------
  1685. ;
  1686. ; Restore the original vector
  1687. ;
  1688. ; Entry Conditions:
  1689. ;
  1690. ; Exit Conditions:
  1691. ;     Nothing
  1692.  
  1693.     public    _loadirqvector
  1694. _loadirqvector  proc
  1695.     push    es
  1696.  
  1697.         les     ax,OldIRQRoutine
  1698.     mov    bx,es
  1699.     or    bx,ax
  1700.     jnz    @F
  1701.  
  1702.     lea    ax,OurIntVector
  1703.     mov    dx,cs
  1704.  
  1705.     mov    bl,[TheIRQChannel]
  1706.     call    FFAR ptr _getirqoffset
  1707.  
  1708.     push    ds
  1709.     sub    cx,cx
  1710.     mov    ds,cx
  1711.  
  1712.     disable
  1713.     xchg    ds:[bx+0],ax
  1714.     xchg    ds:[bx+2],dx
  1715.     enable
  1716.  
  1717.     pop    ds
  1718.  
  1719.     mov    wptr [OldIRQRoutine+0],ax
  1720.     mov    wptr [OldIRQRoutine+2],dx
  1721. ;
  1722. @@:
  1723.     pop    es
  1724.     ret
  1725.  
  1726. _loadirqvector    endp
  1727. ;
  1728. endif    ; MISC2OBJ
  1729. if MISC2OBJ
  1730. ;
  1731. ;---------------------------====< OurIntVector >====---------------------------
  1732. ;
  1733. ; OurIntVector    -- process DMA interrupts
  1734. ;
  1735.  
  1736. intsemaphore    db    -1        ; -1 free, 0+ locked
  1737.  
  1738.     public    OurIntVector
  1739. OurIntVector    proc
  1740.     push    dx
  1741.     push    ax
  1742.         push    ds
  1743.  
  1744. if MODELSIZE eq 0
  1745.     mov    ax,cs            ; tiny (.com) model uses cs segment
  1746. else
  1747.     mov    ax,@data        ; all others use their data segments
  1748. endif
  1749.     mov    ds,ax
  1750.  
  1751.     mov    dx,INTRCTLRST        ; clear the interrupt
  1752.         xor     dx,[_MVTranslateCode]           ; xlate the board address
  1753.     in    al,dx
  1754.  
  1755.         test    al,bISsampbuff          ; our interrupt?
  1756.     jz    skip_int        ; no, continue on...
  1757.  
  1758.     out    dx,al            ; yes, flush it...
  1759.  
  1760.     mov    al,EOI            ; clear the interrupt
  1761.     cmp    TheIRQChannel,8     ; 2nd IRQ controller?
  1762.     jb    @F
  1763.     out    IRQ2ACKREG,al
  1764.     ;
  1765.     @@:
  1766.     out    IRQ1ACKREG,al
  1767.  
  1768.         inc     [NumberOfInterrupts]
  1769.  
  1770.     inc    cs:[intsemaphore]
  1771.         jnz     oiv_done
  1772.  
  1773.     sti                ; let interrupts go while we work
  1774.  
  1775.     cmp    wptr [UserRoutine+2],0    ; call the user function?
  1776.     jz    oiv_done        ; no, just exit
  1777.  
  1778.     call    dword ptr [UserRoutine]
  1779. ;
  1780. oiv_done:
  1781.     dec    cs:[intsemaphore]
  1782. ;
  1783. exit_int:
  1784.     pop    ds
  1785.     pop    ax
  1786.     pop    dx
  1787.     iret
  1788. ;
  1789. skip_int:
  1790.     pushf
  1791.     call    dword ptr ds:[OldIRQRoutine] ; perform the old interrupt
  1792.     jmp    short exit_int
  1793.  
  1794. OurIntVector    endp
  1795. ;
  1796. endif    ; MISC2OBJ
  1797. if PCMOBJ
  1798. ;
  1799. ;---------------------------====< SetupPCMDMAIO >====--------------------------
  1800. ;
  1801. ; SetupPCMDMAIO  --  Setup to output to the DAC
  1802. ;
  1803.     public    SetupPCMDMAIO
  1804. SetupPCMDMAIO   proc
  1805.     push    es
  1806.     push    di
  1807.     les    di,[mvhwShadowPointer]
  1808. ;
  1809. ; setup the sample rate timer
  1810. ;
  1811.         call    _ASloadtimer0
  1812. ;
  1813. ; Setup the Sample Buffer Counter Timer (T1 & rate generator)
  1814. ;
  1815.         mov     ax,[DMABuffLength]      ; get the count
  1816.     sub    dx,dx
  1817.     add    ax,1            ; make it 1 based (1 - 64k)
  1818.     adc    dx,dx
  1819.     mov    cl,[DMABUffDivides]    ; get the buffer size
  1820.     sub    ch,ch
  1821.     div    cx            ; now, we must be flexible
  1822.  
  1823.     mov    bl,[TheDMAChannel]    ; is this a 16 bit channel?
  1824.     mov    bh,[SampleSize]     ; CX = sample size, channel
  1825.  
  1826.     sub    cx,cx            ; ch = multiplier, cl=divider
  1827.     cmp    bx,0003h        ; 8 bits on 8 bit channel?
  1828.     jbe    @F            ; yes, continue on...
  1829.  
  1830.     inc    cx            ; divide by 2
  1831.     cmp    bx,0007h        ; 8 bits on 16 bit channel?
  1832.     jbe    @F            ; yes, continue on...
  1833.  
  1834.     xchg    ch,cl            ; multiply by 2
  1835.     cmp    bx,0203h        ; 16 bits on 8 bit channel?
  1836.     jbe    @F            ; yes, continue on...
  1837.     sub    cx,cx            ; no multiply or divide
  1838.     ;
  1839.     @@:
  1840.         shr     ax,cl                   ; if 8 on 16 divide by 2
  1841.     xchg    ch,cl
  1842.     shl    ax,cl            ; if 16 on 8 multiply by 2
  1843.  
  1844.     sub    cx,cx            ; The buffer size is # of bytes, so
  1845.     neg    bh            ; we must convert it to the data size
  1846.     adc    cx,cx
  1847.     shr    ax,cl
  1848.  
  1849.         call    FFAR ptr _ASloadtimer1
  1850. ;
  1851. ; Setup the system interrupt mask (IRQ mask)
  1852. ;
  1853.     mov    dx,IRQ1MASKREG
  1854.     cmp    TheIRQChannel,8     ; 2nd IRQ controller?
  1855.     jl    @F
  1856.     mov    dl,IRQ2MASKREG
  1857.     ;
  1858.     @@:
  1859.     in    al,dx            ; get the mask
  1860.     mov    ah,TheIRQMask
  1861.     not    ah
  1862.     and    al,ah            ; unmask the correct IRQ
  1863.     out    dx,al            ; then let the system know
  1864. ;
  1865. ; Setup the Interrupt Control Register
  1866. ;
  1867.     mov    dx,INTRCTLRST        ; flush any pending interrupts
  1868.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1869.     out    dx,al            ; of the PCM circuitry
  1870.  
  1871.         mov     dx,INTRCTLR
  1872.         xor     dx,[_MVTranslateCode]           ; xlate the board address
  1873.     in    al,dx            ; get the real mask
  1874.     or    al,bICsampbuff        ; interrupt on sample buffer count
  1875.     out    dx,al            ; send it..
  1876.     mov    es:[di._intrctlr],al    ; save it..
  1877. ;
  1878. ; enable the 12/16 bit stuff
  1879. ;
  1880.     test    [_MVHWVersionBits],bMV101 ; 101 chip?
  1881.     jz    sdhpas1_05          ; no, don't touch this...
  1882.  
  1883.     mov    cx,((NOT(bSC216bit+bSC212bit))*256) + bSC216bit+bSC212bit
  1884.     cmp    [SampleSize],1        ; 12 bit?
  1885.     jz    @F
  1886.     mov    cx,((NOT(bSC216bit+bSC212bit))*256) + bSC216bit
  1887.     cmp    [SampleSize],2        ; 16 bit?
  1888.     jz    @F
  1889.     mov    cx,((NOT(bSC216bit+bSC212bit))*256) + 0
  1890.     ;
  1891.     @@:
  1892.     mov    dx,SYSCONFIG2
  1893.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1894.     in    al,dx
  1895.     and    al,ch            ; clear the bits
  1896.     or    al,cl            ; set the appropriate bits
  1897.     out    dx,al
  1898.     ;
  1899.     sdhpas1_05:
  1900. ;
  1901. ; setup the direction, stereo/mono and DMA enable bits
  1902. ;
  1903.     mov    al,bCCmono        ; get the stereo/mono mask bit
  1904.     and    al,[StereoMono]     ; al = bCCmono if in mono mode
  1905.     or    al,[PCMDirection]    ; get the direction bit mask
  1906.     or    al,bCCenapcm        ; enable the PCM state machine
  1907.         mov     dx,CROSSCHANNEL
  1908.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1909.     mov    ah,0fh + bCCdrq     ; get a mask to load non PCM bits
  1910.     and    ah,es:[di._crosschannel]; grab all but PCM/DRQ/MONO/DIRECTION
  1911.     or    al,ah            ; merge the two states
  1912.     xor    al,bCCenapcm        ; disable the PCM bit
  1913.     out    dx,al            ; send to the hardware
  1914.     xor    al,bCCenapcm        ; enable the PCM bit
  1915.     out    dx,al            ; send to the hardware
  1916.     mov    es:[di._crosschannel],al; and save the new state
  1917. ;
  1918. ; Setup the audio filter sample bits
  1919. ;
  1920.     mov    al,es:[di._audiofilt]
  1921.     or    al,(bFIsrate+bFIsbuff)    ; enable the sample count/buff counters
  1922.     mov    dx,AUDIOFILT
  1923.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1924.     out    dx,al
  1925.     mov    es:[di._audiofilt],al
  1926.  
  1927.         mov     NumberOfInterrupts,0
  1928.  
  1929.         enable                          ; Fly, baby Fly!!!
  1930.  
  1931.     pop    di
  1932.     pop    es
  1933.     ret
  1934.  
  1935. SetupPCMDMAIO    endp
  1936. ;
  1937. ;
  1938. ;---------------------------====< SetupPCMPolledIO >====-----------------------
  1939. ;
  1940. ; SetupPCMPolledIO  --    Setup to read/write to the ADC/DAC in a polled fashion
  1941. ;
  1942.     public    SetupPCMPolledIO
  1943. SetupPCMPolledIO        proc
  1944.     push    es
  1945.     push    di
  1946.     les    di,[mvhwShadowPointer]
  1947. ;
  1948. ; Setup the Sample Timer (T0 & square wave output)
  1949. ;
  1950.     call    _ASloadTimer0
  1951. ;
  1952. ; Setup the Sample Buffer Counter Timer (T1 & rate generator)
  1953. ;
  1954.     mov    ax,1            ; get the count
  1955.     call    FFAR ptr _ASloadtimer1
  1956. ;
  1957. ; Setup the Interrupt Control Register
  1958. ;
  1959.         mov     dx,INTRCTLR
  1960.     xor    dx,[_MVTranslateCode]       ; xlate the board address
  1961.     in    al,dx               ; get the real mask
  1962.     or    al,bICsampbuff+bICsamprate ; enable both sample timer ints
  1963.     out    dx,al               ; send it...
  1964.     mov    es:[di._intrctlr],al       ; save it...
  1965. ;
  1966. ; enable the 16 bit stuff
  1967. ;
  1968.     test    [_MVHWVersionBits],bMV101 ; 101 chip?
  1969.     jz    sphpas1_05          ; no, don't touch this...
  1970.  
  1971.     mov    cx,((NOT(bSC216bit+bSC212bit))*256) + bSC216bit+bSC212bit
  1972.     cmp    [SampleSize],1        ; 12 bit?
  1973.     jz    @F
  1974.     mov    cx,((NOT(bSC216bit+bSC212bit))*256) + bSC216bit
  1975.     cmp    [SampleSize],2        ; 16 bit?
  1976.     jz    @F
  1977.     mov    cx,((NOT(bSC216bit+bSC212bit))*256) + 0
  1978.     ;
  1979.     @@:
  1980.     mov    dx,SYSCONFIG2
  1981.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1982.     in    al,dx
  1983.     and    al,ch            ; clear the bits
  1984.     or    al,cl            ; set the appropriate bits
  1985.     out    dx,al
  1986.     ;
  1987.     sphpas1_05:
  1988. ;
  1989. ; setup the direction, stereo/mono and DMA enable bits
  1990. ;
  1991.     mov    al,bCCmono        ; get the stereo/mono mask bit
  1992.     and    al,[StereoMono]     ; al = bCCmono if in mono mode
  1993.     or    al,[PCMDirection]    ; get the direction bit mask
  1994.     or    al,bCCenapcm + bCCdrq    ; enable the PCM & set DRQ for NOT mask
  1995.         mov     dx,CROSSCHANNEL
  1996.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  1997.     mov    ah,0fh            ; get a mask to load the non-PCM bits
  1998.     and    ah,es:[di._crosschannel]; grab all but PCM/DRQ/MONO/DIRECTION
  1999.     or    al,ah            ; merge the two states
  2000.     xor    al,bCCenapcm + bCCdrq    ; disable the PCM & DRQ
  2001.     out    dx,al            ; send to the hardware
  2002.     xor    al,bCCenapcm        ; enable the PCM
  2003.     out    dx,al
  2004.     mov    es:[di._crosschannel],al; and save the new state
  2005. ;
  2006. ; Setup the audio filter sample bits to enable sample timer/count
  2007. ;
  2008.     mov    al,es:[di._audiofilt]
  2009.     or    al,(bFIsrate+bFIsbuff)    ; enable the sample timer/counter
  2010.     mov    dx,AUDIOFILT
  2011.     xor    dx,[_MVTranslateCode]    ; xlate the board address
  2012.     out    dx,al
  2013.     mov    es:[di._audiofilt],al
  2014.  
  2015.         sub     ax,ax
  2016.     mov    NumberOfInterrupts,ax
  2017.  
  2018.         enable
  2019.  
  2020.     pop    di
  2021.     pop    es
  2022.     ret
  2023.  
  2024. SetupPCMPolledIO   endp
  2025. ;
  2026. ;
  2027. ;----------------------------====< StartPlaying >====--------------------------
  2028. ;
  2029.     public    StartPlaying
  2030. StartPlaying    proc
  2031. ;
  2032. ; Save the type of setup. It contains the interrupt masks needed
  2033. ;
  2034.     mov    [TypeOfSetup],DMAOUTPUT
  2035.     mov    [PCMDirection],bCCdac    ; bit d6 of interrupt control register
  2036. ;
  2037. ; Select the DMA mode for playing
  2038. ;
  2039.     mov    al,10h            ; auto init bit on 8237 chip
  2040.     and    al,[DMAAutoInit]    ; al may have the auto-init bit
  2041.     or    al,48h            ; merge in the rest of the DMA bits
  2042.     mov    TheDMAMode,al        ; save the mode
  2043. ;
  2044. ; Program the DMA, then our board circuitry to start the interrupts
  2045. ;
  2046.         call    LoadDMA                 ; setup the DMA controller
  2047.     call    SetupPCMDMAIO        ; Setup the MV Hardware
  2048.  
  2049.     mov    StatusWord,1        ; set the global status word
  2050.  
  2051.         ret
  2052.  
  2053. StartPlaying    endp
  2054. ;
  2055. ;
  2056. ;---------------------------====< StartRecording >====-------------------------
  2057. ;
  2058.     public    StartRecording
  2059. StartRecording    proc
  2060. ;
  2061. ; Save the type of setup. It contains the interrupt masks needed
  2062. ;
  2063.     mov    [TypeOfSetup],DMAINPUT
  2064.     mov    [PCMDirection],00h    ; bit d6 of interrupt control register
  2065. ;
  2066. ; Select the DMA mode for recording
  2067. ;
  2068.     mov    al,10h            ; auto init bit on 8237 chip
  2069.     and    al,[DMAAutoInit]    ; al may have the auto-init bit
  2070.     or    al,44h            ; merge in the rest of the DMA bits
  2071.     mov    TheDMAMode,al        ; save the mode
  2072. ;
  2073. ; Program the DMA, then our board circuitry to start the interrupts
  2074. ;
  2075.         call    LoadDMA                 ; setup the DMA controller
  2076.     call    SetupPCMDMAIO        ; Setup the MV Hardware
  2077.  
  2078.     mov    StatusWord,2        ; set the global status word
  2079.         ret
  2080.  
  2081. StartRecording    endp
  2082. ;
  2083. endif    ; PCMOBJ
  2084. if MISC2OBJ
  2085. ;
  2086. ;---------------------====< _unloadirqvector >====---------------
  2087. ;
  2088. ; Restore the original vector
  2089. ;
  2090. ; Entry Conditions:
  2091. ;     dParm1 points to the user routine
  2092. ;
  2093. ; Exit Conditions:
  2094. ;     Nothing
  2095. ;
  2096. ;
  2097.     public    _unloadirqvector
  2098. _unloadirqvector    proc
  2099.     push    es
  2100.  
  2101.         les     ax,OldIRQRoutine
  2102.     mov    bx,es
  2103.     or    bx,ax
  2104.     jz    @F
  2105.  
  2106.     mov    bl,[TheIRQChannel]
  2107.     call    _getirqoffset
  2108.  
  2109.     push    ds
  2110.     sub    cx,cx
  2111.     mov    ds,cx
  2112.  
  2113.         disable
  2114.     mov    ds:[bx+0],ax
  2115.     mov    ds:[bx+2],es
  2116.         enable
  2117.  
  2118.     pop    ds
  2119.  
  2120.         sub     ax,ax
  2121.     mov    wptr [OldIRQRoutine+0],ax
  2122.     mov    wptr [OldIRQRoutine+2],ax
  2123. ;
  2124. @@:
  2125.     pop    es
  2126.     ret
  2127.  
  2128. _unloadirqvector    endp
  2129.  
  2130. endif    ; MISC2OBJ
  2131.  
  2132.     end
  2133.  
  2134.